using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;

using System.Web.Security;
using System.Web;
using System.DirectoryServices;
using System.Security.Principal;
using System.Net.Mail;
using System.Data.SqlClient;
using System.Text.RegularExpressions;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Utilities;
using System.Configuration;
using System.Diagnostics;
using EAT.Common;

namespace EAT.ExternalCollaboration
{
    
    /*++
     class AddExternalUserPage
     
     This class provides functionality for the AddExternalUser application page (aeu.aspx).
     This allows the user to query Membership for the existence of an account.  It allows
     for provisioning if the account does not exist.  Permissions / roles can be assigned.
     Email is sent, depending upon the configured workflow settings.
    --*/

    public class AddExternalUserPage : Microsoft.SharePoint.WebControls.LayoutsPageBase
    {
        SqlManager SqlM;
        protected EAT.Common.cUserManager UM;
        protected EAT.Common.SPHelper SPH;

        //
        // The web page user enters the user name into the TextBox
        // tbUsername.
        //
        protected System.Web.UI.WebControls.TextBox tbUsername;

        //
        // The user clicks the Button btnLookup to query the Membership 
        // directory for the existence of the user specified in tbUsername.
        //
        protected System.Web.UI.WebControls.ImageButton btnLookup;

        //
        // The results of the lookup appear in the Label lblLookupResult.
        //
        protected System.Web.UI.WebControls.Label lblLookupResult;

        //
        // If the user does not exist, the the LinkButton lnkProvision
        // becomes visible, and allows the web site user to initiate
        // the external user provisioning process.
        //
        protected System.Web.UI.WebControls.LinkButton lnkProvision;

        //
        // The Label lblProvision displays the results of the provisioning
        // request.
        //
        protected System.Web.UI.WebControls.Label lblProvision;

        //
        // The Password string stores the random generated password.
        //
        protected String Password;

        //
        // A boolean indicating if user provisioning workflow is enabled.
        // Different behavior keys off of this value.
        //
        protected Boolean bWorkFlowEnabled = true;

        //
        // A label to print out the status of permission addition and email notification.
        //
        protected System.Web.UI.WebControls.Label lblPermission;

        //
        // Radio button to select between adding the user to a group or assigning explicit permission.
        //
        protected System.Web.UI.WebControls.RadioButton radAddToGroup;
        protected System.Web.UI.WebControls.RadioButton radAddToRole;

        protected System.Web.UI.WebControls.Button btnAddAndEmail;

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern int RevertToSelf();

        //
        // cblRoles lets the user choose a role for the new account.
        //
        protected System.Web.UI.WebControls.CheckBoxList cblRoles;

        //
        // ddlGroups lets the user choose a group for the new account.
        //
        protected System.Web.UI.WebControls.DropDownList ddlGroups;

        protected String EmailBody;
        protected String EmailSubject;

        public AddExternalUserPage()
        {
            SqlM = new SqlManager();
            UM = new Common.cUserManager(
                                ConfigurationManager.ConnectionStrings["ADAMConnectionString"].ConnectionString
                                );
            SPH = new Common.SPHelper();

        }

        public void btnLookup_Click(
                        object sender, 
                        EventArgs e
                        )
        {
            //
            // Hide the provision link button and clean the label text.
            //
            lnkProvision.Visible = false;
            lblProvision.Text = null;

            cUserManager um = new cUserManager(
                                      );

            if (um.IsValidUsername(tbUsername.Text) == false)
            {
                throw new SystemException(Resources.aeuNotValidEmailAddressText);
            }

            //
            // Check if the user is in the Membership directory.  Display
            // the results in the label.
            //
            WindowsIdentity wi = null;
            bool bReverted = false;

            try
            {
                //wi = WindowsIdentity.GetCurrent();
                //RevertToSelf();
                //bReverted = true;
                //WindowsIdentity.GetCurrent().Impersonate();
                if (Membership.GetUser(
                                   tbUsername.Text
                                   ) != null)
                {
                    lblLookupResult.Text = string.Format(Resources.aeuUserExistsText, HttpUtility.HtmlEncode(tbUsername.Text));

                    lblProvision.Text += "<br>" + Resources.aeuPermissionsLabel;


                    //
                    // Enable the permission radios
                    //
                    radAddToGroup.Enabled = true;
                    radAddToRole.Enabled = true;
                    radRoleGroup_OnClick(sender, e);
                    btnAddAndEmail.Enabled = true;
                }
                else
                {
                    lblLookupResult.Text = string.Format(Resources.aeuUserNotFoundText, HttpUtility.HtmlEncode(tbUsername.Text)) + "<br>";

                    //
                    // Disable the permission radios
                    //
                    radAddToGroup.Enabled = false;
                    radAddToRole.Enabled = false;
                    btnAddAndEmail.Enabled = false;

                    //
                    // If the user does not exist then display the provision link button.
                    //
                    lnkProvision.Visible = true;
                }
            }
            catch (Exception ex)
            {
                lblLookupResult.Text += ex.Message;
            }
            finally
            {
                if (wi != null && bReverted)
                {
                    wi.Impersonate();
                }
            }
        }

        public void radRoleGroup_OnClick(object sender, EventArgs e)
        {
            if (radAddToGroup.Checked)
            {
                ddlGroups.Enabled = true;
                cblRoles.Enabled = false;
            }
            else
            {
                ddlGroups.Enabled = false;
                cblRoles.Enabled = true;
            }
        }

        public void lnkProvision_Click(
                        object sender, 
                        EventArgs e
                        )
        {
            //
            // Generate a password to use for the new account.
            //
            Password = Membership.GeneratePassword(9, 2);

            try
            {
                //
                // Instantiate a UserManager and connect to the LDAP server.
                //
                cUserManager um = new cUserManager(
                                          ConfigurationManager.ConnectionStrings["ADAMConnectionString"].ConnectionString
                                          );

                if (um.IsValidUsername(tbUsername.Text) == false)
                {
                    throw new SystemException(Resources.aeuNotValidEmailAddressText);
                }

                MembershipCreateStatus status;

                //
                // Create the user with the new password.  Use a sentinel value for the 
                // secret password.  If workflow is enabled, then create the user in a 
                // disabled state.
                //
                WindowsIdentity wi = null;
                bool bReverted = false;
               
                try
                {
                    wi = WindowsIdentity.GetCurrent();
                    RevertToSelf();
                    bReverted = true;
                    WindowsIdentity.GetCurrent().Impersonate();

                    MembershipUser User = Membership.CreateUser(
                                                         tbUsername.Text,
                                                         Password,
                                                         tbUsername.Text,
                                                         "[change the secret question]",
                                                         Membership.GeneratePassword(9, 2),
                                                         !bWorkFlowEnabled,
                                                         out status
                                                         );
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    if (wi != null && bReverted)
                    {
                        wi.Impersonate();
                    }
                }

                //
                // Store the account requester in the LDAP store.
                //
                String Provisioner = SPContext.Current.Web.CurrentUser.Email;

                if (Provisioner == "" || Provisioner == null)
                {
                    Provisioner = SPContext.Current.Web.CurrentUser.Name;
                }
                um.SetProvisioner(tbUsername.Text, Provisioner);
            }
            catch (Exception ex)
            {
                lblProvision.Text += ex.Message;
                return;
            }

            if (bWorkFlowEnabled == false)
            {
                //
                // Note the success of the operation in the Provision label.
                //
                lblProvision.Text = string.Format(Resources.aeuUserRegisteredText, HttpUtility.HtmlEncode(tbUsername.Text)) + "<br>\n";
            }

            //
            // Enable the permission radios.
            //
            radAddToGroup.Enabled = true;
            radAddToRole.Enabled = true;
            btnAddAndEmail.Enabled = true;
            radRoleGroup_OnClick(sender, e);

            //
            // Hide the provision link.
            // Clear the text describing the success / failure of the initial 
            // lookup operation.
            //
            lnkProvision.Visible = false;
            lblLookupResult.Text = null;
            PrepareEmail();
            SendEmail();
        }

        protected void Page_Load()
        {
            SPWeb web = SPContext.Current.Web;

            if (SPH.IsAdmin(web) == false)
            {
                cblRoles.Enabled = false;
                ddlGroups.Enabled = false;
                btnAddAndEmail.Enabled = false;
                btnLookup.Enabled = false;
                tbUsername.Enabled = false;
                radAddToGroup.Enabled = false;
                radAddToRole.Enabled = false;
                Response.Redirect("/_layouts/AccessDenied.aspx");
                return;
            }

            if (SqlM.GetEntry("Config", "UACWorkflowApprovers") == null ||
                SqlM.GetEntry("Config", "UACWorkflowApprovers") == "")
            {
                bWorkFlowEnabled = false;
            }
            else
            {
                bWorkFlowEnabled = true;
            }

            if (!Page.IsPostBack)
            {
                ConstructPermissions();
            }
        }

        protected void ConstructPermissions()
        {
            SPWeb web = SPContext.Current.Web;
            String[] roles = new string[web.RoleDefinitions.Count];
            int i = 0;

            //
            // Set the roles string array to the names of the 
            // web roles.  Bind the cblRoles to this array.
            //

            foreach (SPRoleDefinition rd in web.RoleDefinitions)
            {
                roles[i++] = rd.Name;
            }
            cblRoles.DataSource = roles;
            cblRoles.DataBind();

            String[] groups = new string[web.Groups.Count];
            i = 0;
            foreach (SPGroup g in web.Groups)
            {
                groups[i++] = g.Name;
            }
            ddlGroups.DataSource = groups;
            ddlGroups.DataBind();
        }

        protected void PrepareEmail()
        {
            //
            // if workflow is enabled then the user is created in a disabled state.  Mail is sent
            // to the ADAM administrator.
            //
            if (bWorkFlowEnabled)
            {
                EmailSubject = Resources.aeuWorkflowEmailSubjectText;
                
                // 
                // We may want to add the site to the email.
                // Use SPContext.Current.Site.Url.ToString();
                //

                EmailBody += string.Format(Resources.aeuWorkflowEmailBodyText, Web.CurrentUser.Name, HttpUtility.HtmlEncode(tbUsername.Text), SqlM.GetEntry("Config", "ManagementURL"));
            }
            else
            {
                EmailSubject = Resources.aeuNoWorkflowEmailSubjectText;

                EmailBody += string.Format(Resources.aeuNoWorkflowEmailBodyText, HttpUtility.HtmlEncode(tbUsername.Text), Password);
            }
        }

        protected void SendEmail()
        {
            System.Net.Mail.MailMessage mm = new System.Net.Mail.MailMessage();
            WindowsIdentity wi = null;
            bool bReverted = false;

            // 
            // Add the user to the permission group or role, and send the email.
            // Revert to the process context to manipulate permission information.
            // 
            try
            {
                wi = WindowsIdentity.GetCurrent();
                RevertToSelf();
                bReverted = true;
                WindowsIdentity.GetCurrent().Impersonate();

                SPWeb web = SPContext.Current.Web;

                if (bWorkFlowEnabled == false)
                {
                    //
                    // Send email only to the user who is provisioning the account.
                    //
                    SPUser u = web.CurrentUser;
                    mm.To.Add(new MailAddress(u.Email));
                }
                else
                {
                    SPGroup UACApproveGroup = null;

                    //
                    // Send email to the SP group that is responsible for doing approvals.
                    //
                    using (SPSite site = new SPSite(SqlM.GetEntry("Config", "ManagementURL")))
                    {
                        using (SPWeb adminWeb = site.OpenWeb())
                        {
                            UACApproveGroup = adminWeb.SiteGroups[SqlM.GetEntry("Config", "UACWorkflowApprovers")];
                        }
                    }
                    foreach (SPUser user in UACApproveGroup.Users)
                    {
                        if (user.Email != null && user.Email != "")
                        {
                            mm.To.Add(new MailAddress(user.Email));
                        }
                    }
                }

                mm.From = new MailAddress(
                                  SqlM.GetEntry("Config", "eMailSource")
                                  );

                mm.Subject = EmailSubject;
                mm.Body = EmailBody;

                SmtpClient sc = new SmtpClient();
                sc.Send(mm);
                if (bWorkFlowEnabled)
                {
                    lblProvision.Text += Resources.aeuAdminMustApproveText;
                }
                else
                {
                    lblProvision.Text += Resources.aeuSelectPermissionsText;

                    //
                    // Mark the user as having a generated password.
                    //
                    DirectoryEntry de = UM.FindUser(tbUsername.Text);
                    de.Properties["eatmuPwdGenerated"].Value = true;
                    de.CommitChanges();
                }
            }
            catch (Exception ex)
            {
                lblProvision.Text += ex.Message;
            }
            finally
            {
                if (wi != null && bReverted)
                {
                    wi.Impersonate();
                }
            }
        }

        protected void btnGrantPermission_Click(
                           Object sender, 
                           EventArgs e
                           )
        {
            // 
            // Add the user to the permission group or role.
            // 
            try
            {
                string RedirectUrl = null;
                SPUser NewUser = null;
                SPWeb web = SPContext.Current.Web;

                //
                // The following block gets the user registered in SharePoint.
                //
                SPSecurity.RunWithElevatedPrivileges(
                    delegate() 
                    {
                        using (SPSite s = new SPSite(this.Page.Request.Url.ToString()))
                        {
                            s.AllowUnsafeUpdates = true;
                            using (SPWeb w = s.OpenWeb())
                            {
                                w.AllowUnsafeUpdates = true;
                                NewUser = w.EnsureUser(tbUsername.Text);
                                w.AllowUnsafeUpdates = false;
                            }
                            s.AllowUnsafeUpdates = false;
                        }
                    }
                );

                //
                // Now add the user to the correct group in the correct site.
                //
                SPSecurity.RunWithElevatedPrivileges(
                    delegate()
                    {
                        using (SPSite s = new SPSite(this.Site.Url.ToString()))
                        {
                            s.AllowUnsafeUpdates = true;
                            using (SPWeb w = s.RootWeb)
                            {
                                w.AllowUnsafeUpdates = true;
                                if (radAddToGroup.Checked == true)
                                {
                                    foreach (SPGroup g in w.Groups)
                                    {
                                        if (g.Name == ddlGroups.SelectedItem.Value)
                                        {
                                            g.AddUser(NewUser);
                                            RedirectUrl = w.Url.ToString() + "/_layouts/people.aspx?MembershipGroupId=" + g.ID;
                                        }
                                    }
                                }
                                else
                                {
                                    if (cblRoles.SelectedItem != null)
                                    {
                                        foreach (SPRoleDefinition rd in w.RoleDefinitions)
                                        {
                                            if (rd.Name == cblRoles.SelectedItem.Value)
                                            {
                                                SPRoleAssignment ra = new SPRoleAssignment(NewUser);
                                                ra.RoleDefinitionBindings.Add(rd);
                                                w.RoleAssignments.Add(ra);
                                            }
                                        }
                                        RedirectUrl = web.Url.ToString() + "/_layouts/user.aspx";
                                    }
                                    else
                                    {
                                        lblPermission.Text = "<br>" + Resources.aeuNoPermissionSelectedText;
                                    }
                                }

                                w.AllowUnsafeUpdates = false;
                            }
                            s.AllowUnsafeUpdates = false;
                        }
                    }
                );
                Response.Redirect(RedirectUrl);
            }
            catch (Exception ex)
            {
                lblPermission.Text += ex.Message;
            }
        }
    }
    
}
